/*
Decorator 装饰器是一项实验性特性，在未来的版本中可能会发生改变
它们不仅增加了代码的可读性，清晰地表达了意图，而且提供一种方便的手段，增加或修改类的功能

若要启用实验性的装饰器特性，你必须在命令行或tsconfig.json里启用编译器选项

"experimentalDecorators": true,                 // Enable experimental support for legacy experimental decorators.        装饰器语法限制
"emitDecoratorMetadata": true,                  // Emit design-type metadata for decorated declarations in source files.  装饰器语法限制

装饰器
装饰器是一种特殊类型的声明，它能够被附加到类声明，方法， 访问符，属性或参数上。

https://xiaoman.blog.csdn.net/article/details/122630296
https://www.bookstack.cn/read/es6-3rd/spilt.1.docs-decorator.md
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
// 1.类装饰器  ClassDecorator target 构造函数也就是会被装饰的类
// 2.属性装饰器  PropertyDecorator target 原型对象，不是构造函数
// 3.参数装饰器  ParameterDecorator target 原型对象，不是构造函数
// 4.方法装饰器  MethodDecorator target 原型对象，不是构造函数
// 5.装饰器工厂 又名函数科里化
// 6.import 'reflect-metadata'  元数据库
// 7.axios  封装了node环境和浏览器环境的请求方法
// 1.类装饰器  ClassDecorator target 构造函数
/*
  @decorator

  class A {}

  // 等同于
  class A {}

  A = decorator(A) || A;
  也就是说，装饰器是一个对类进行处理的函数。
  装饰器函数的第一个参数，就是所要装饰的目标类。

  为类添加一个静态属性，如果想添加实例属性，可以通过目标类的prototype对象操作。
  target.prototype.xxx = "xxx"
*/
/*
const Base: ClassDecorator = (target) => {
  target.prototype.xiaoli = "xiaoli"
  target.prototype.fn = () => {
    console.log("我是哈哈哈")
  }
}

@Base // 也可以写成Base(Http)
class Http {
  // 原来类的属性和方法
}

const http = new Http() as any
http.fn()
*/
// 5.装饰器工厂 又名函数科里化
const Base = (name) => {
    const fn = (target) => {
        // console.log(target)
        target.prototype.name = name;
        target.prototype.fn = () => {
            // console.log("我是哈哈哈")
        };
    };
    return fn;
};
import axios from "axios";
import "reflect-metadata";
const Get = (url) => {
    const fn = (target, key, descriptor) => {
        // console.log(target, key, descriptor)  // {} getList { value: [Function: getList], writable: true, enumerable: false, configurable: true }
        // target.prototype.url = url // 不能这样写，因为target是原型对象，不是构造函数
        // target.__proto__.url = url // 不能这样写，因为target是原型对象，不是构造函数
        const k = Reflect.getMetadata('key', target); // result
        axios.get(url).then(res => {
            // descriptor.value(res.data)
            descriptor.value(k ? res.data[k] : res.data);
        });
    };
    return fn;
};
// 参数的装饰器先执行，再执行方法的装饰器
const Result = () => {
    const fn = (target, key, index) => {
        Reflect.defineMetadata('key', 'result', target);
        // console.log(target, key, index)   // {} getList 0
    };
    return fn;
};
const Name = (target, key) => {
    // console.log(target, key)    // {} xiaoman
};
let Http = class Http {
    constructor() {
        this.xiaoman = '小满';
    }
    getList(data) {
        // console.log(data.result.list)
        console.log(data.list, 5555);
    }
    create() { }
};
__decorate([
    Name,
    __metadata("design:type", String)
], Http.prototype, "xiaoman", void 0);
__decorate([
    Get('https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10'),
    __param(0, Result()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", void 0)
], Http.prototype, "getList", null);
Http = __decorate([
    Base("xiaoli"),
    __metadata("design:paramtypes", [])
], Http);
const http = new Http();
// http.fn()
// console.log(http.name)
console.log(http.getList("111111"), 3333);
